home *** CD-ROM | disk | FTP | other *** search
/ MacFormat 1999 Spring / macformat-077.iso / Shareware Plus / Development / SpriteWorld 2.2 Extra Demos / User Contributions / ButtonBreakOut ƒ / SpritePersistence / SpritePersistence.note < prev   
Encoding:
Text File  |  1999-01-11  |  8.9 KB  |  200 lines  |  [TEXT/CWIE]

  1. /*———————————————————————————————————————————————————————————————————————————————————————————————————
  2.                                     SPRITE PERSISTENCE README
  3.                                     —————————————————————————
  4.  
  5.     • INTRO - WHAT IS IT
  6.  
  7.     This is a framework module for saving/reloading part or all of the data belonging:
  8.         - to all the sprites in a spriteworld, 
  9.         - or to all the sprites in a given layer (that's the main objective of this thing), 
  10.         - or even to a single sprite (for special purposes I suppose). 
  11.     It works with DataPersistence for disk services.
  12.     It's very small, 2K *including* DataPersistence (!), and as easy to use as we could 
  13.     make it.
  14.     At this time, only the sprite positions are saved, since any other info would probably be very 
  15.     application-specific. Saving and reloading other sprite info is as easy as going into the 
  16.     SpritePersistence.c file, and adding more lines to SWGCopyFromSpriteToRecord and 
  17.     SWGCopyFromRecordToSprite (see the paragraph: COMPLETELY ADAPTABLE FOR ANY APPLICATION)
  18.  
  19.     Cool. Is it useful? Glad you asked.
  20.  
  21.  
  22.     • HOW DID IT COME ABOUT ?
  23.  
  24.     This was initially intended to be added to Matthew's ButtonSprite, which we find
  25.     very useful (matthewf@panix.com)
  26.  
  27.     ButtonSprite allows using sprites as buttons. It is very easy to set up and to use, and 
  28.     is structured in a way quite consistent with SW. (Good for you, Matthew)
  29.  
  30.     As an additional goodie, it allows moving the buttons around using the mouse. Perfect when 
  31.     you're tweaking your interface a lot. Much better than the usual shuttling between resedit,
  32.     rebuilding your app, then rerunning it, and back again. BUT the new buttons' positions are 
  33.     forgotten when you quit.
  34.  
  35.     This is what SpritePersistence provides for. The main facility we wanted is saving/restoring 
  36.     the position of all sprites IN A GIVEN LAYER, into/from a resource file. As an extension, we 
  37.     provide for easily saving/loading ALL sprites in a spriteworld with a single function call; 
  38.     or you may, if you wish, save or reload a single sprite. These facilities might perhaps
  39.     make this module useful in many situations. 
  40.  
  41.     The actual file I/O is done by the DataPersistence module (see 'DataPersistence.note').
  42.  
  43.  
  44.     • COMPLETELY ADAPTABLE FOR ANY APPLICATION
  45.  
  46.     The basic routines presented here simply save/restore the sprite's positions. This was the 
  47.     original goal for the module. But they also provide an easily modified framework for making 
  48.     persistent more of, or even all the data belonging to sprites, including the 
  49.     application-specific data which you probably associated to SpriteWorld's SpriteRec.
  50.  
  51.     You just have to :
  52.  
  53.     1. modify the tSpriteSaveRec record declaration in the SpritePersistence.h header: include 
  54.     a declaration for each of the data fields you want to save;
  55.  
  56.     2. add the necessary store/load intructions for your data fields, respectively in the 
  57.     SWGCopyFromSpriteToRecord and SWGCopyFromRecordToSprite routines. Take a look at how the 
  58.     sprite coordinates are loaded/stored to see how straightforward it is.
  59.     
  60.     That's all you need to do to adapt this module for saving/restoring your own data structures.
  61.  
  62.  
  63.     • USAGE
  64.     
  65.     1. To save, call:
  66.  
  67.                  SWGSaveSpritesInLayer (yourLayerP);                                // a SpritePtr
  68.     or 
  69.                  SWGSaveSpritesInAllLayers (yourWorldP);                            // a SpriteWorldPtr
  70.     or 
  71.                 SWGSaveSingleSprite (layerNum, spriteNum, yourSpriteP);            // SInt16, SInt16, SpritePtr
  72.  
  73.     2. To load, call:
  74.  
  75.                  SWGLoadSpritesInLayer (yourLayerP);                                // a SpritePtr
  76.     or 
  77.                  SWGLoadSpritesInAllLayers (yourWorldP);                            // a SpriteWorldPtr
  78.     or 
  79.                 SWGLoadSingleSprite (layerNum, spriteNum, yourSpriteP);            // SInt16, SInt16, SpritePtr
  80.  
  81.     In the case of single sprites, for building the layerNum and spriteNum arguments, simply call: 
  82.  
  83.                 layerNum = SWGGetLayerNumber (yourLayerP);
  84.                 spriteNum = SWGGetSpriteNumber (yourSpriteP);
  85.  
  86.     or you may prefer:
  87.  
  88.                 SWGSaveSingleSprite         (SWGGetLayerNumber (yourLayerP), 
  89.                                         SWGGetSpriteNumber (yourSpriteP), 
  90.                                         yourSpriteP);
  91.  
  92.     SWGGetLayerNumber and SWGGetSpriteNumber do have a little overhead, but very little (for the first 
  93.     one, very _very_ little). They both simply follow the links from yourLayerP or yourSpriteP until the 
  94.     head of the list, counting the steps. They should be quite fast with the usual number of layers and 
  95.     sprites. Moreover they are only useful in conjunction with _single-sprite_ I/O; the layer and 
  96.     world I/O have no overhead at all.
  97.  
  98.     If you have many hundreds of sprites, SWGGetSpriteNumber would be proportionally slowed down, 
  99.     but you probably wouldn't use single sprite random I/O in the middle of an animation. 
  100.     
  101.     If you _do_ have zillions of sprites, and need to save or load individual sprite data right in 
  102.     the middle of a tricky animation, you should simply precompute the sprite numbers and keep them.
  103.     For instance store them in the sprite's userData field, or better, in your own sprite-related data
  104.     record. After creating the sprites (and locking the world), call SWGGetSpriteNumber once for every 
  105.     sprite, and store the resulting numbers. This will only cost 2 bytes per sprite, i.e. 1K if you
  106.     use 500 sprites (I don't know of anyone who uses that many).
  107.  
  108.  
  109.     • FILE MANAGEMENT
  110.  
  111.     File usage is transparent, SpritePersistence opens and closes the file when needed.
  112.  
  113.     For more details, see 'DataPersistence.note'.
  114.  
  115.  
  116.     • EXCEPTIONS, SPECIAL CASES
  117.  
  118.     When one of the SWGLoadSpritesXXX routines does not find the expected resources, it does 
  119.     nothing: the sprites will be left in their original state. There's a good reason for 
  120.     this: if your program starts by loading sprite data, it will work even the first time, 
  121.     when the file is empty.
  122.  
  123.     You still have, of course, in your app, to initialize the sprites to default parameters, 
  124.     since these will be used as default values the very first time, or when you have trashed 
  125.     the save file.
  126.  
  127.  
  128.     • FAQ
  129.  
  130.     ----- 1 -----
  131.  
  132.     Q: Don't I need to open/close the external save file? I notice you didn't.
  133.  
  134.     A: No, you don't need to. This is handled automatically by SpritePersistence. By default, 
  135.     the external save file behaves, from your point of view, as a (physically separate) extension 
  136.     of your own resource fork.
  137.  
  138.     You just use the calls described above as if the file didn't exist. It will be opened 
  139.     automatically, and closed before returning. Don't worry about it, it's simple and efficient; 
  140.     and as a bonus, data safety is about as good as it can reasonably get, since the written 
  141.     data gets flushed to disk when the file is closed.
  142.  
  143.     If however you prefer to do the open/close yourself, just do it. SpritePersistence will notice 
  144.     that you did, and won't interfere with you: won't try to reopen it, and won't close it when done.
  145.     e.g.:
  146.             err = SWGOpenSpriteSaveFile ();
  147.  
  148.                 // ... your processing ... 
  149.  
  150.             SWGSaveSingleSprite (layerNum, spriteNum, yourSpriteP);        // any number of times
  151.  
  152.                 // ... your processing ... 
  153.  
  154.             SWGLoadSingleSprite (layerNum, spriteNum, yourSpriteP);        // any number of times
  155.  
  156.                 // ... your processing ... 
  157.  
  158.             SWGCloseSpriteSaveFile ();
  159.  
  160.     This may be advisable if you wish to do single-sprite access; in that case, the 
  161.     automatic file open and close wouldn't be efficient. Even so, if the accesses are not 
  162.     very frequent, or not in the middle of a tricky animation, you may prefer to use the 
  163.     automatic open feature, in most cases there won't be a noticeable performance hit.
  164.  
  165.     ----- 2 -----
  166.  
  167.     Q: Why the layerNum and spriteNum arguments in SWGSave/LoadSingleSprite?
  168.     A: Because they are used, with to kMaxSpritesInOneLayer, to compute the resource ID for 
  169.     each sprite:    
  170.                 id = layerNum * kMaxSpritesInOneLayer + spriteNum.  
  171.     Think of the layerNum as a vertical coord, the spriteNum as a horizontal coord, 
  172.     kMaxSpritesInOneLayer as rowBytes, and the resulting ID as a screen address...
  173.  
  174.     There is no drawback to having a big kMaxSpritesInOneLayer, except you must keep the value
  175.     layerNum * kMaxSpritesInOneLayer * spriteNum inside the acceptable values for a resource 
  176.     ID (< 2^15). For most purposes, 100 <= kMaxSpritesInOneLayer <= 200 is probably ok. 
  177.     But if you think you may have e.g. 369 sprites (if all your sprites explode at once :), just 
  178.     put in 400. Even if you have 10 layers, the highest record number would then be 4369.
  179.  
  180.     ----- 3 -----
  181.  
  182.      Q: Why use the resource format?
  183.      A: Why resources at all? Because they are convenient, and there are utilities for doing
  184.      various things with resources. It's widely known that resource read/write *may* be less 
  185.      efficient than custom data formats, but that's only a concern for a high number of items, 
  186.      say many thousands. That's not what this module is aimed at. 
  187.      
  188.      However, if this module is _ever_ used heavily enough to discover cases where performance 
  189.      becomes an issue, it would be fairly easy to modify the two routines which do actual 
  190.      file access, and manage a custom data format (if you want to do it yourself, please 
  191.      send me the source :).
  192.  
  193.  
  194.      • TO DO
  195.  
  196.     - TilePersistence: the same service for tiles that SpritePersistence provides for sprites.
  197.  
  198. ———————————————————————————————————————————————————————————————————————————————————————————————————*/
  199. // feedback: macdev@tnuctip.com
  200.